alita-sdk 0.3.462__py3-none-any.whl → 0.3.627__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- alita_sdk/cli/agent/__init__.py +5 -0
- alita_sdk/cli/agent/default.py +258 -0
- alita_sdk/cli/agent_executor.py +15 -3
- alita_sdk/cli/agent_loader.py +56 -8
- alita_sdk/cli/agent_ui.py +93 -31
- alita_sdk/cli/agents.py +2274 -230
- alita_sdk/cli/callbacks.py +96 -25
- alita_sdk/cli/cli.py +10 -1
- alita_sdk/cli/config.py +162 -9
- alita_sdk/cli/context/__init__.py +30 -0
- alita_sdk/cli/context/cleanup.py +198 -0
- alita_sdk/cli/context/manager.py +731 -0
- alita_sdk/cli/context/message.py +285 -0
- alita_sdk/cli/context/strategies.py +289 -0
- alita_sdk/cli/context/token_estimation.py +127 -0
- alita_sdk/cli/input_handler.py +419 -0
- alita_sdk/cli/inventory.py +1073 -0
- alita_sdk/cli/testcases/__init__.py +94 -0
- alita_sdk/cli/testcases/data_generation.py +119 -0
- alita_sdk/cli/testcases/discovery.py +96 -0
- alita_sdk/cli/testcases/executor.py +84 -0
- alita_sdk/cli/testcases/logger.py +85 -0
- alita_sdk/cli/testcases/parser.py +172 -0
- alita_sdk/cli/testcases/prompts.py +91 -0
- alita_sdk/cli/testcases/reporting.py +125 -0
- alita_sdk/cli/testcases/setup.py +108 -0
- alita_sdk/cli/testcases/test_runner.py +282 -0
- alita_sdk/cli/testcases/utils.py +39 -0
- alita_sdk/cli/testcases/validation.py +90 -0
- alita_sdk/cli/testcases/workflow.py +196 -0
- alita_sdk/cli/toolkit.py +14 -17
- alita_sdk/cli/toolkit_loader.py +35 -5
- alita_sdk/cli/tools/__init__.py +36 -2
- alita_sdk/cli/tools/approval.py +224 -0
- alita_sdk/cli/tools/filesystem.py +910 -64
- alita_sdk/cli/tools/planning.py +389 -0
- alita_sdk/cli/tools/terminal.py +414 -0
- alita_sdk/community/__init__.py +72 -12
- alita_sdk/community/inventory/__init__.py +236 -0
- alita_sdk/community/inventory/config.py +257 -0
- alita_sdk/community/inventory/enrichment.py +2137 -0
- alita_sdk/community/inventory/extractors.py +1469 -0
- alita_sdk/community/inventory/ingestion.py +3172 -0
- alita_sdk/community/inventory/knowledge_graph.py +1457 -0
- alita_sdk/community/inventory/parsers/__init__.py +218 -0
- alita_sdk/community/inventory/parsers/base.py +295 -0
- alita_sdk/community/inventory/parsers/csharp_parser.py +907 -0
- alita_sdk/community/inventory/parsers/go_parser.py +851 -0
- alita_sdk/community/inventory/parsers/html_parser.py +389 -0
- alita_sdk/community/inventory/parsers/java_parser.py +593 -0
- alita_sdk/community/inventory/parsers/javascript_parser.py +629 -0
- alita_sdk/community/inventory/parsers/kotlin_parser.py +768 -0
- alita_sdk/community/inventory/parsers/markdown_parser.py +362 -0
- alita_sdk/community/inventory/parsers/python_parser.py +604 -0
- alita_sdk/community/inventory/parsers/rust_parser.py +858 -0
- alita_sdk/community/inventory/parsers/swift_parser.py +832 -0
- alita_sdk/community/inventory/parsers/text_parser.py +322 -0
- alita_sdk/community/inventory/parsers/yaml_parser.py +370 -0
- alita_sdk/community/inventory/patterns/__init__.py +61 -0
- alita_sdk/community/inventory/patterns/ast_adapter.py +380 -0
- alita_sdk/community/inventory/patterns/loader.py +348 -0
- alita_sdk/community/inventory/patterns/registry.py +198 -0
- alita_sdk/community/inventory/presets.py +535 -0
- alita_sdk/community/inventory/retrieval.py +1403 -0
- alita_sdk/community/inventory/toolkit.py +173 -0
- alita_sdk/community/inventory/toolkit_utils.py +176 -0
- alita_sdk/community/inventory/visualize.py +1370 -0
- alita_sdk/configurations/__init__.py +1 -1
- alita_sdk/configurations/ado.py +141 -20
- alita_sdk/configurations/bitbucket.py +0 -3
- alita_sdk/configurations/confluence.py +76 -42
- alita_sdk/configurations/figma.py +76 -0
- alita_sdk/configurations/gitlab.py +17 -5
- alita_sdk/configurations/openapi.py +329 -0
- alita_sdk/configurations/qtest.py +72 -1
- alita_sdk/configurations/report_portal.py +96 -0
- alita_sdk/configurations/sharepoint.py +148 -0
- alita_sdk/configurations/testio.py +83 -0
- alita_sdk/runtime/clients/artifact.py +3 -3
- alita_sdk/runtime/clients/client.py +353 -48
- alita_sdk/runtime/clients/sandbox_client.py +0 -21
- alita_sdk/runtime/langchain/_constants_bkup.py +1318 -0
- alita_sdk/runtime/langchain/assistant.py +123 -26
- alita_sdk/runtime/langchain/constants.py +642 -1
- alita_sdk/runtime/langchain/document_loaders/AlitaExcelLoader.py +103 -60
- alita_sdk/runtime/langchain/document_loaders/AlitaJSONLinesLoader.py +77 -0
- alita_sdk/runtime/langchain/document_loaders/AlitaJSONLoader.py +6 -3
- alita_sdk/runtime/langchain/document_loaders/AlitaPowerPointLoader.py +226 -7
- alita_sdk/runtime/langchain/document_loaders/AlitaTextLoader.py +5 -2
- alita_sdk/runtime/langchain/document_loaders/constants.py +12 -7
- alita_sdk/runtime/langchain/langraph_agent.py +279 -73
- alita_sdk/runtime/langchain/utils.py +82 -15
- alita_sdk/runtime/llms/preloaded.py +2 -6
- alita_sdk/runtime/skills/__init__.py +91 -0
- alita_sdk/runtime/skills/callbacks.py +498 -0
- alita_sdk/runtime/skills/discovery.py +540 -0
- alita_sdk/runtime/skills/executor.py +610 -0
- alita_sdk/runtime/skills/input_builder.py +371 -0
- alita_sdk/runtime/skills/models.py +330 -0
- alita_sdk/runtime/skills/registry.py +355 -0
- alita_sdk/runtime/skills/skill_runner.py +330 -0
- alita_sdk/runtime/toolkits/__init__.py +7 -0
- alita_sdk/runtime/toolkits/application.py +21 -9
- alita_sdk/runtime/toolkits/artifact.py +15 -5
- alita_sdk/runtime/toolkits/datasource.py +13 -6
- alita_sdk/runtime/toolkits/mcp.py +139 -251
- alita_sdk/runtime/toolkits/mcp_config.py +1048 -0
- alita_sdk/runtime/toolkits/planning.py +178 -0
- alita_sdk/runtime/toolkits/skill_router.py +238 -0
- alita_sdk/runtime/toolkits/subgraph.py +251 -6
- alita_sdk/runtime/toolkits/tools.py +238 -32
- alita_sdk/runtime/toolkits/vectorstore.py +11 -5
- alita_sdk/runtime/tools/__init__.py +3 -1
- alita_sdk/runtime/tools/application.py +20 -6
- alita_sdk/runtime/tools/artifact.py +511 -28
- alita_sdk/runtime/tools/data_analysis.py +183 -0
- alita_sdk/runtime/tools/function.py +43 -15
- alita_sdk/runtime/tools/image_generation.py +50 -44
- alita_sdk/runtime/tools/llm.py +852 -67
- alita_sdk/runtime/tools/loop.py +3 -1
- alita_sdk/runtime/tools/loop_output.py +3 -1
- alita_sdk/runtime/tools/mcp_remote_tool.py +25 -10
- alita_sdk/runtime/tools/mcp_server_tool.py +7 -6
- alita_sdk/runtime/tools/planning/__init__.py +36 -0
- alita_sdk/runtime/tools/planning/models.py +246 -0
- alita_sdk/runtime/tools/planning/wrapper.py +607 -0
- alita_sdk/runtime/tools/router.py +2 -4
- alita_sdk/runtime/tools/sandbox.py +9 -6
- alita_sdk/runtime/tools/skill_router.py +776 -0
- alita_sdk/runtime/tools/tool.py +3 -1
- alita_sdk/runtime/tools/vectorstore.py +7 -2
- alita_sdk/runtime/tools/vectorstore_base.py +51 -11
- alita_sdk/runtime/utils/AlitaCallback.py +137 -21
- alita_sdk/runtime/utils/constants.py +5 -1
- alita_sdk/runtime/utils/mcp_client.py +492 -0
- alita_sdk/runtime/utils/mcp_oauth.py +202 -5
- alita_sdk/runtime/utils/mcp_sse_client.py +36 -7
- alita_sdk/runtime/utils/mcp_tools_discovery.py +124 -0
- alita_sdk/runtime/utils/serialization.py +155 -0
- alita_sdk/runtime/utils/streamlit.py +6 -10
- alita_sdk/runtime/utils/toolkit_utils.py +16 -5
- alita_sdk/runtime/utils/utils.py +36 -0
- alita_sdk/tools/__init__.py +113 -29
- alita_sdk/tools/ado/repos/__init__.py +51 -33
- alita_sdk/tools/ado/repos/repos_wrapper.py +148 -89
- alita_sdk/tools/ado/test_plan/__init__.py +25 -9
- alita_sdk/tools/ado/test_plan/test_plan_wrapper.py +23 -1
- alita_sdk/tools/ado/utils.py +1 -18
- alita_sdk/tools/ado/wiki/__init__.py +25 -8
- alita_sdk/tools/ado/wiki/ado_wrapper.py +291 -22
- alita_sdk/tools/ado/work_item/__init__.py +26 -9
- alita_sdk/tools/ado/work_item/ado_wrapper.py +56 -3
- alita_sdk/tools/advanced_jira_mining/__init__.py +11 -8
- alita_sdk/tools/aws/delta_lake/__init__.py +13 -9
- alita_sdk/tools/aws/delta_lake/tool.py +5 -1
- alita_sdk/tools/azure_ai/search/__init__.py +11 -8
- alita_sdk/tools/azure_ai/search/api_wrapper.py +1 -1
- alita_sdk/tools/base/tool.py +5 -1
- alita_sdk/tools/base_indexer_toolkit.py +170 -45
- alita_sdk/tools/bitbucket/__init__.py +17 -12
- alita_sdk/tools/bitbucket/api_wrapper.py +59 -11
- alita_sdk/tools/bitbucket/cloud_api_wrapper.py +49 -35
- alita_sdk/tools/browser/__init__.py +5 -4
- alita_sdk/tools/carrier/__init__.py +5 -6
- alita_sdk/tools/carrier/backend_reports_tool.py +6 -6
- alita_sdk/tools/carrier/run_ui_test_tool.py +6 -6
- alita_sdk/tools/carrier/ui_reports_tool.py +5 -5
- alita_sdk/tools/chunkers/__init__.py +3 -1
- alita_sdk/tools/chunkers/code/treesitter/treesitter.py +37 -13
- alita_sdk/tools/chunkers/sematic/json_chunker.py +1 -0
- alita_sdk/tools/chunkers/sematic/markdown_chunker.py +97 -6
- alita_sdk/tools/chunkers/universal_chunker.py +270 -0
- alita_sdk/tools/cloud/aws/__init__.py +10 -7
- alita_sdk/tools/cloud/azure/__init__.py +10 -7
- alita_sdk/tools/cloud/gcp/__init__.py +10 -7
- alita_sdk/tools/cloud/k8s/__init__.py +10 -7
- alita_sdk/tools/code/linter/__init__.py +10 -8
- alita_sdk/tools/code/loaders/codesearcher.py +3 -2
- alita_sdk/tools/code/sonar/__init__.py +10 -7
- alita_sdk/tools/code_indexer_toolkit.py +73 -23
- alita_sdk/tools/confluence/__init__.py +21 -15
- alita_sdk/tools/confluence/api_wrapper.py +78 -23
- alita_sdk/tools/confluence/loader.py +4 -2
- alita_sdk/tools/custom_open_api/__init__.py +12 -5
- alita_sdk/tools/elastic/__init__.py +11 -8
- alita_sdk/tools/elitea_base.py +493 -30
- alita_sdk/tools/figma/__init__.py +58 -11
- alita_sdk/tools/figma/api_wrapper.py +1235 -143
- alita_sdk/tools/figma/figma_client.py +73 -0
- alita_sdk/tools/figma/toon_tools.py +2748 -0
- alita_sdk/tools/github/__init__.py +13 -14
- alita_sdk/tools/github/github_client.py +224 -100
- alita_sdk/tools/github/graphql_client_wrapper.py +119 -33
- alita_sdk/tools/github/schemas.py +14 -5
- alita_sdk/tools/github/tool.py +5 -1
- alita_sdk/tools/github/tool_prompts.py +9 -22
- alita_sdk/tools/gitlab/__init__.py +15 -11
- alita_sdk/tools/gitlab/api_wrapper.py +207 -41
- alita_sdk/tools/gitlab_org/__init__.py +10 -8
- alita_sdk/tools/gitlab_org/api_wrapper.py +63 -64
- alita_sdk/tools/google/bigquery/__init__.py +13 -12
- alita_sdk/tools/google/bigquery/tool.py +5 -1
- alita_sdk/tools/google_places/__init__.py +10 -8
- alita_sdk/tools/google_places/api_wrapper.py +1 -1
- alita_sdk/tools/jira/__init__.py +17 -11
- alita_sdk/tools/jira/api_wrapper.py +91 -40
- alita_sdk/tools/keycloak/__init__.py +11 -8
- alita_sdk/tools/localgit/__init__.py +9 -3
- alita_sdk/tools/localgit/local_git.py +62 -54
- alita_sdk/tools/localgit/tool.py +5 -1
- alita_sdk/tools/memory/__init__.py +11 -3
- alita_sdk/tools/non_code_indexer_toolkit.py +1 -0
- alita_sdk/tools/ocr/__init__.py +11 -8
- alita_sdk/tools/openapi/__init__.py +490 -114
- alita_sdk/tools/openapi/api_wrapper.py +1368 -0
- alita_sdk/tools/openapi/tool.py +20 -0
- alita_sdk/tools/pandas/__init__.py +20 -12
- alita_sdk/tools/pandas/api_wrapper.py +38 -25
- alita_sdk/tools/pandas/dataframe/generator/base.py +3 -1
- alita_sdk/tools/postman/__init__.py +11 -11
- alita_sdk/tools/pptx/__init__.py +10 -9
- alita_sdk/tools/pptx/pptx_wrapper.py +1 -1
- alita_sdk/tools/qtest/__init__.py +30 -10
- alita_sdk/tools/qtest/api_wrapper.py +430 -13
- alita_sdk/tools/rally/__init__.py +10 -8
- alita_sdk/tools/rally/api_wrapper.py +1 -1
- alita_sdk/tools/report_portal/__init__.py +12 -9
- alita_sdk/tools/salesforce/__init__.py +10 -9
- alita_sdk/tools/servicenow/__init__.py +17 -14
- alita_sdk/tools/servicenow/api_wrapper.py +1 -1
- alita_sdk/tools/sharepoint/__init__.py +10 -8
- alita_sdk/tools/sharepoint/api_wrapper.py +4 -4
- alita_sdk/tools/slack/__init__.py +10 -8
- alita_sdk/tools/slack/api_wrapper.py +2 -2
- alita_sdk/tools/sql/__init__.py +11 -9
- alita_sdk/tools/testio/__init__.py +10 -8
- alita_sdk/tools/testrail/__init__.py +11 -8
- alita_sdk/tools/testrail/api_wrapper.py +1 -1
- alita_sdk/tools/utils/__init__.py +9 -4
- alita_sdk/tools/utils/content_parser.py +77 -3
- alita_sdk/tools/utils/text_operations.py +410 -0
- alita_sdk/tools/utils/tool_prompts.py +79 -0
- alita_sdk/tools/vector_adapters/VectorStoreAdapter.py +17 -13
- alita_sdk/tools/xray/__init__.py +12 -9
- alita_sdk/tools/yagmail/__init__.py +9 -3
- alita_sdk/tools/zephyr/__init__.py +9 -7
- alita_sdk/tools/zephyr_enterprise/__init__.py +11 -8
- alita_sdk/tools/zephyr_essential/__init__.py +10 -8
- alita_sdk/tools/zephyr_essential/api_wrapper.py +30 -13
- alita_sdk/tools/zephyr_essential/client.py +2 -2
- alita_sdk/tools/zephyr_scale/__init__.py +11 -9
- alita_sdk/tools/zephyr_scale/api_wrapper.py +2 -2
- alita_sdk/tools/zephyr_squad/__init__.py +10 -8
- {alita_sdk-0.3.462.dist-info → alita_sdk-0.3.627.dist-info}/METADATA +147 -7
- alita_sdk-0.3.627.dist-info/RECORD +468 -0
- alita_sdk-0.3.627.dist-info/entry_points.txt +2 -0
- alita_sdk-0.3.462.dist-info/RECORD +0 -384
- alita_sdk-0.3.462.dist-info/entry_points.txt +0 -2
- {alita_sdk-0.3.462.dist-info → alita_sdk-0.3.627.dist-info}/WHEEL +0 -0
- {alita_sdk-0.3.462.dist-info → alita_sdk-0.3.627.dist-info}/licenses/LICENSE +0 -0
- {alita_sdk-0.3.462.dist-info → alita_sdk-0.3.627.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
DEFAULT_PROMPT = """You are **Alita**, a Testing Agent running in a terminal-based CLI assistant. Alita is an open-source, agentic testing interface. You are expected to be precise, safe, technical, and helpful.
|
|
2
|
+
|
|
3
|
+
Your capabilities:
|
|
4
|
+
|
|
5
|
+
- Receive user prompts and other context provided by the harness, such as files in the workspace, logs, test suites, reports, screenshots, API specs, and documentation.
|
|
6
|
+
- Communicate with the user by streaming thinking & responses, and by making & updating plans.
|
|
7
|
+
- Emit function calls to run terminal commands, execute test suites, inspect environments, analyze artifacts, and apply patches when tests require updates. Depending on configuration, you may request that these function calls be escalated for approval before executing.
|
|
8
|
+
|
|
9
|
+
Within this context, **Alita** refers to the open-source agentic testing interface (not any legacy language model).
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# How you work
|
|
14
|
+
|
|
15
|
+
## Personality
|
|
16
|
+
|
|
17
|
+
You are concise, direct, and friendly. You communicate efficiently and always prioritize actionable test insights. You clearly state assumptions, environment prerequisites, and next steps. Unless explicitly asked, you avoid excessively verbose explanations.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# AGENTS.md spec
|
|
22
|
+
|
|
23
|
+
`AGENTS.md` files in repositories may contain instructions for working in that specific container — including test conventions, folder structure, naming rules, frameworks in use, test data handling, or how to run validations.
|
|
24
|
+
|
|
25
|
+
Rules:
|
|
26
|
+
|
|
27
|
+
- The scope of an `AGENTS.md` file covers its entire directory subtree.
|
|
28
|
+
- Any file you touch must follow instructions from applicable `AGENTS.md` files.
|
|
29
|
+
- For conflicting instructions, deeper directory `AGENTS.md` takes precedence.
|
|
30
|
+
- Direct system/developer/user instructions always take precedence.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Responsiveness
|
|
35
|
+
|
|
36
|
+
### Preamble messages
|
|
37
|
+
|
|
38
|
+
Before running tool calls (executing tests, launching commands, applying patches), send a brief preface describing what you’re about to do. It should:
|
|
39
|
+
|
|
40
|
+
- Be short (8–12 words)
|
|
41
|
+
- Group related actions together
|
|
42
|
+
- Refer to previous context when relevant
|
|
43
|
+
- Keep a light and collaborative tone
|
|
44
|
+
|
|
45
|
+
Example patterns:
|
|
46
|
+
|
|
47
|
+
- “Analyzing failing tests next to identify the root cause.”
|
|
48
|
+
- “Running backend API tests now to reproduce the reported issue.”
|
|
49
|
+
- “About to patch selectors and re-run UI regression tests.”
|
|
50
|
+
- “Finished scanning logs; now checking flaky test patterns.”
|
|
51
|
+
- “Next I’ll generate missing test data and rerun.”
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Planning
|
|
56
|
+
|
|
57
|
+
Use `update_plan` when:
|
|
58
|
+
|
|
59
|
+
- Tasks involve multiple phases of testing
|
|
60
|
+
- The sequence of activities matters
|
|
61
|
+
- Ambiguity requires breaking down the approach
|
|
62
|
+
- The user requests step-wise execution
|
|
63
|
+
|
|
64
|
+
### Resuming existing plans
|
|
65
|
+
|
|
66
|
+
**Important**: Before creating a new plan, check if there's already an existing plan in progress:
|
|
67
|
+
|
|
68
|
+
- If the user says "continue" or similar, look at the current plan state shown in tool results
|
|
69
|
+
- If steps are already marked as completed (☑), **do not create a new plan** — continue executing the remaining uncompleted steps
|
|
70
|
+
- Only use `update_plan` to create a **new** plan when starting a fresh task
|
|
71
|
+
- Use `complete_step` to mark steps done as you finish them
|
|
72
|
+
|
|
73
|
+
When resuming after interruption (e.g., tool limit reached):
|
|
74
|
+
|
|
75
|
+
1. Review which steps are already completed (☑)
|
|
76
|
+
2. Identify the next uncompleted step (☐)
|
|
77
|
+
3. Continue execution from that step — do NOT recreate the plan
|
|
78
|
+
4. Mark steps complete as you go
|
|
79
|
+
|
|
80
|
+
Example of a **high-quality test-oriented plan**:
|
|
81
|
+
|
|
82
|
+
1. Reproduce failure locally
|
|
83
|
+
2. Capture failing logs + stack traces
|
|
84
|
+
3. Identify root cause in test or code
|
|
85
|
+
4. Patch locator + stabilize assertions
|
|
86
|
+
5. Run whole suite to confirm no regressions
|
|
87
|
+
|
|
88
|
+
Low-quality plans ("run tests → fix things → done") are not acceptable.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Task execution
|
|
93
|
+
|
|
94
|
+
You are a **testing agent**, not just a code-writing agent. Your responsibilities include:
|
|
95
|
+
|
|
96
|
+
- Executing tests across frameworks (API, UI, mobile, backend, contract, load, security)
|
|
97
|
+
- Analyzing logs, failures, screenshots, metrics, stack traces
|
|
98
|
+
- Investigating flakiness, nondeterminism, environmental issues
|
|
99
|
+
- Generating missing tests or aligning test coverage to requirements
|
|
100
|
+
- Proposing (and applying when asked) patches to fix the root cause of test failures
|
|
101
|
+
- Updating and creating test cases, fixtures, mocks, test data and configs
|
|
102
|
+
- Validating integrations (CI/CD, containers, runners, environments)
|
|
103
|
+
- Surfacing reliability and coverage gaps
|
|
104
|
+
|
|
105
|
+
When applying patches, follow repository style and AGENTS.md rules.
|
|
106
|
+
Avoid modifying unrelated code and avoid adding technical debt.
|
|
107
|
+
|
|
108
|
+
Common use cases include:
|
|
109
|
+
|
|
110
|
+
- Test execution automation
|
|
111
|
+
- Manual exploratory testing documentation
|
|
112
|
+
- Test case generation from requirements
|
|
113
|
+
- Assertions improvements and selector stabilization
|
|
114
|
+
- Test coverage analysis
|
|
115
|
+
- Defect reproduction and debugging
|
|
116
|
+
- Root cause attribution (test vs product defect)
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Handling files
|
|
121
|
+
|
|
122
|
+
### CRITICAL: File creation and modification rules
|
|
123
|
+
|
|
124
|
+
**NEVER output entire file contents in your response.** Always use tools to write files.
|
|
125
|
+
|
|
126
|
+
When creating or modifying files:
|
|
127
|
+
|
|
128
|
+
1. **Use incremental writes for new files**: Create files in logical sections using multiple tool calls:
|
|
129
|
+
- First call: Create file with initial structure (imports, class definition header)
|
|
130
|
+
- Subsequent calls: Add methods, functions, or sections one at a time using edit/append
|
|
131
|
+
- This prevents context overflow and ensures each part is properly written
|
|
132
|
+
|
|
133
|
+
2. **Use edit tools for modifications**: Use `filesystem_edit_file` for precise text replacement instead of rewriting entire files
|
|
134
|
+
|
|
135
|
+
3. **Never dump code in chat**: If you find yourself about to write a large code block in your response, STOP and use a file tool instead
|
|
136
|
+
|
|
137
|
+
Example - creating a test file correctly:
|
|
138
|
+
```
|
|
139
|
+
# Call 1: Create file with structure
|
|
140
|
+
filesystem_write_file("test_api.py", "import pytest\\nimport requests\\n\\n")
|
|
141
|
+
|
|
142
|
+
# Call 2: Append first test class/method
|
|
143
|
+
filesystem_append_file("test_api.py", "class TestAPI:\\n def test_health(self):\\n assert requests.get('/health').status_code == 200\\n")
|
|
144
|
+
|
|
145
|
+
# Call 3: Append second test method
|
|
146
|
+
filesystem_append_file("test_api.py", "\\n def test_auth(self):\\n assert requests.get('/protected').status_code == 401\\n")
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Why this matters**: Large file outputs can exceed token limits, cause truncation, or fail silently. Incremental writes are reliable and verifiable.
|
|
150
|
+
|
|
151
|
+
### Reading large files
|
|
152
|
+
|
|
153
|
+
When working with large files (logs, test reports, data files, source code):
|
|
154
|
+
|
|
155
|
+
- **Read in chunks**: Use offset and limit parameters to read files in manageable sections (e.g., 500-1000 lines at a time)
|
|
156
|
+
- **Start with structure**: First scan the file to understand its layout before diving into specific sections
|
|
157
|
+
- **Target relevant sections**: Once you identify the area of interest, read only that portion in detail
|
|
158
|
+
- **Avoid full loads**: Loading entire large files into context can cause models to return empty or incomplete responses due to context limitations
|
|
159
|
+
|
|
160
|
+
Example approach:
|
|
161
|
+
1. Read first 100 lines to understand file structure
|
|
162
|
+
2. Search/grep for relevant patterns to locate target sections
|
|
163
|
+
3. Read specific line ranges where issues or relevant code exist
|
|
164
|
+
|
|
165
|
+
### Writing and updating files
|
|
166
|
+
|
|
167
|
+
When modifying files, especially large ones:
|
|
168
|
+
|
|
169
|
+
- **Update in pieces**: Make targeted edits to specific sections, paragraphs, or functions rather than rewriting entire files
|
|
170
|
+
- **Use precise replacements**: Replace exact strings with sufficient context (3-5 lines before/after) to ensure unique matches
|
|
171
|
+
- **Batch related changes**: Group logically related edits together, but keep each edit focused and minimal
|
|
172
|
+
- **Preserve structure**: Maintain existing formatting, indentation, and file organization
|
|
173
|
+
- **Avoid full rewrites**: Never regenerate an entire file when only a portion needs changes
|
|
174
|
+
|
|
175
|
+
### Context limitations warning
|
|
176
|
+
|
|
177
|
+
**Important**: When context becomes too large (many files, long outputs, extensive history), some models may return empty or truncated responses. If you notice this:
|
|
178
|
+
|
|
179
|
+
- Summarize previous findings before continuing
|
|
180
|
+
- Focus on one file or task at a time
|
|
181
|
+
- Clear irrelevant context from consideration
|
|
182
|
+
- Break complex operations into smaller, sequential steps
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Sandbox and approvals
|
|
187
|
+
|
|
188
|
+
Sandboxing and approval rules are identical to coding agents, but framed around testing actions:
|
|
189
|
+
|
|
190
|
+
You may need escalation before:
|
|
191
|
+
|
|
192
|
+
- Creating or modifying files
|
|
193
|
+
- Installing testing dependencies
|
|
194
|
+
- Running network-dependent test suites
|
|
195
|
+
- Performing destructive cleanup actions
|
|
196
|
+
- Triggering CI pipelines or test runs that write outside workspace
|
|
197
|
+
|
|
198
|
+
If sandbox modes and approval rules are not specified, assume:
|
|
199
|
+
|
|
200
|
+
- Filesystem: `workspace-write`
|
|
201
|
+
- Network: ON
|
|
202
|
+
- Approval: `on-failure`
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Validating your work
|
|
207
|
+
|
|
208
|
+
Validation is core to your job.
|
|
209
|
+
|
|
210
|
+
- After fixing tests, rerun only the relevant subset first
|
|
211
|
+
- If stable, run broader suites to validate no regressions
|
|
212
|
+
- Avoid running full suites unnecessarily when in approval modes that require escalation
|
|
213
|
+
|
|
214
|
+
If there are no tests for the change you made, and the project has an established testing pattern, you may add one.
|
|
215
|
+
|
|
216
|
+
Avoid fixing unrelated tests unless the user requests it.
|
|
217
|
+
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
## Presenting your work and final message
|
|
221
|
+
|
|
222
|
+
Your final message should feel like an update from a senior test engineer handing off state.
|
|
223
|
+
|
|
224
|
+
Good patterns include:
|
|
225
|
+
|
|
226
|
+
- What was tested
|
|
227
|
+
- What failed and why
|
|
228
|
+
- What was fixed
|
|
229
|
+
- Where files were changed
|
|
230
|
+
- How to validate locally
|
|
231
|
+
|
|
232
|
+
You should not dump full file contents unless the user asks. Reference files and paths directly.
|
|
233
|
+
|
|
234
|
+
If relevant, offer optional next steps such as:
|
|
235
|
+
|
|
236
|
+
- Running full regression
|
|
237
|
+
- Adding missing tests
|
|
238
|
+
- Improving coverage or performance
|
|
239
|
+
- Integrating into CI
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Answer formatting rules in CLI
|
|
244
|
+
|
|
245
|
+
Keep results scannable and technical:
|
|
246
|
+
|
|
247
|
+
- Use section headers only where they improve clarity
|
|
248
|
+
- Use short bullet lists (4–6 key bullets)
|
|
249
|
+
- Use backticks for code, commands, test names, file paths
|
|
250
|
+
- Reference files individually to keep them clickable (e.g. `tests/ui/login.spec.ts:44`)
|
|
251
|
+
- Avoid nested bullet lists or long paragraphs
|
|
252
|
+
|
|
253
|
+
Tone: pragmatic, precise, and focused on improving testing reliability and coverage.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
In short: **Alita is a highly technical manual + automated testing agent** that plans intelligently, executes and analyzes tests across frameworks, fixes issues at their root when permitted, and keeps the user informed without noise.
|
|
258
|
+
"""
|
alita_sdk/cli/agent_executor.py
CHANGED
|
@@ -58,13 +58,15 @@ def _create_assistant(client, agent_data: Dict[str, Any], llm, memory, tools: Li
|
|
|
58
58
|
memory=memory,
|
|
59
59
|
store=None,
|
|
60
60
|
debug_mode=False,
|
|
61
|
-
mcp_tokens=None
|
|
61
|
+
mcp_tokens=None,
|
|
62
|
+
persona=agent_data.get('persona', 'quirky'),
|
|
62
63
|
)
|
|
63
64
|
|
|
64
65
|
|
|
65
66
|
def create_agent_executor(client, agent_def: Dict[str, Any], toolkit_configs: List[Dict[str, Any]],
|
|
66
67
|
llm, llm_model: str, llm_temperature: float, llm_max_tokens: int, memory,
|
|
67
|
-
filesystem_tools: Optional[List] = None, mcp_tools: Optional[List] = None
|
|
68
|
+
filesystem_tools: Optional[List] = None, mcp_tools: Optional[List] = None,
|
|
69
|
+
terminal_tools: Optional[List] = None, planning_tools: Optional[List] = None):
|
|
68
70
|
"""Create agent executor for local agents with tools (sync version).
|
|
69
71
|
|
|
70
72
|
Note: mcp_tools parameter is deprecated - use create_agent_executor_with_mcp for MCP support.
|
|
@@ -81,6 +83,10 @@ def create_agent_executor(client, agent_def: Dict[str, Any], toolkit_configs: Li
|
|
|
81
83
|
additional_tools = []
|
|
82
84
|
if filesystem_tools:
|
|
83
85
|
additional_tools.extend(filesystem_tools)
|
|
86
|
+
if terminal_tools:
|
|
87
|
+
additional_tools.extend(terminal_tools)
|
|
88
|
+
if planning_tools:
|
|
89
|
+
additional_tools.extend(planning_tools)
|
|
84
90
|
if mcp_tools:
|
|
85
91
|
additional_tools.extend(mcp_tools)
|
|
86
92
|
|
|
@@ -97,7 +103,9 @@ async def create_agent_executor_with_mcp(
|
|
|
97
103
|
llm_temperature: float,
|
|
98
104
|
llm_max_tokens: int,
|
|
99
105
|
memory,
|
|
100
|
-
filesystem_tools: Optional[List] = None
|
|
106
|
+
filesystem_tools: Optional[List] = None,
|
|
107
|
+
terminal_tools: Optional[List] = None,
|
|
108
|
+
planning_tools: Optional[List] = None
|
|
101
109
|
) -> Tuple[Any, Optional[Any]]:
|
|
102
110
|
"""Create agent executor with MCP tools using persistent sessions.
|
|
103
111
|
|
|
@@ -135,6 +143,10 @@ async def create_agent_executor_with_mcp(
|
|
|
135
143
|
additional_tools = []
|
|
136
144
|
if filesystem_tools:
|
|
137
145
|
additional_tools.extend(filesystem_tools)
|
|
146
|
+
if terminal_tools:
|
|
147
|
+
additional_tools.extend(terminal_tools)
|
|
148
|
+
if planning_tools:
|
|
149
|
+
additional_tools.extend(planning_tools)
|
|
138
150
|
if mcp_tools:
|
|
139
151
|
additional_tools.extend(mcp_tools)
|
|
140
152
|
|
alita_sdk/cli/agent_loader.py
CHANGED
|
@@ -5,13 +5,42 @@ Handles loading agent definitions from various file formats (YAML, JSON, Markdow
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import json
|
|
8
|
+
import locale
|
|
8
9
|
import yaml
|
|
9
10
|
from pathlib import Path
|
|
10
11
|
from typing import Dict, Any
|
|
12
|
+
from pydantic import SecretStr
|
|
11
13
|
|
|
12
14
|
from .config import substitute_env_vars
|
|
13
15
|
|
|
14
16
|
|
|
17
|
+
def _read_text_with_fallbacks(path: Path) -> str:
|
|
18
|
+
"""Read a text file using robust, cross-platform defaults.
|
|
19
|
+
|
|
20
|
+
Why this exists:
|
|
21
|
+
- On Windows, `Path.read_text()` defaults to the system code page (often cp1252).
|
|
22
|
+
Agent definition files are commonly authored as UTF-8 and may include smart quotes
|
|
23
|
+
(e.g. ”) whose UTF-8 byte sequence contains 0x9D, which is *undefined* in cp1252.
|
|
24
|
+
That combination triggers: UnicodeDecodeError: 'charmap' codec can't decode byte 0x9d.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
# 1) Prefer UTF-8 (most common for repo files)
|
|
28
|
+
try:
|
|
29
|
+
return path.read_text(encoding="utf-8")
|
|
30
|
+
except UnicodeDecodeError:
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
# 2) UTF-8 with BOM (common on Windows)
|
|
34
|
+
try:
|
|
35
|
+
return path.read_text(encoding="utf-8-sig")
|
|
36
|
+
except UnicodeDecodeError:
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
# 3) Fall back to the platform preferred encoding, but never crash.
|
|
40
|
+
# This keeps the CLI usable even if a file was authored in a legacy encoding.
|
|
41
|
+
return path.read_text(encoding=locale.getpreferredencoding(False), errors="replace")
|
|
42
|
+
|
|
43
|
+
|
|
15
44
|
def load_agent_definition(file_path: str) -> Dict[str, Any]:
|
|
16
45
|
"""
|
|
17
46
|
Load agent definition from file.
|
|
@@ -31,8 +60,8 @@ def load_agent_definition(file_path: str) -> Dict[str, Any]:
|
|
|
31
60
|
|
|
32
61
|
if not path.exists():
|
|
33
62
|
raise FileNotFoundError(f"Agent definition not found: {file_path}")
|
|
34
|
-
|
|
35
|
-
content = path
|
|
63
|
+
|
|
64
|
+
content = _read_text_with_fallbacks(path)
|
|
36
65
|
|
|
37
66
|
# Handle markdown with YAML frontmatter
|
|
38
67
|
if path.suffix == '.md':
|
|
@@ -57,7 +86,8 @@ def load_agent_definition(file_path: str) -> Dict[str, Any]:
|
|
|
57
86
|
'filesystem_tools_preset': frontmatter.get('filesystem_tools_preset'),
|
|
58
87
|
'filesystem_tools_include': frontmatter.get('filesystem_tools_include'),
|
|
59
88
|
'filesystem_tools_exclude': frontmatter.get('filesystem_tools_exclude'),
|
|
60
|
-
'mcps': frontmatter.get('mcps', [])
|
|
89
|
+
'mcps': frontmatter.get('mcps', []),
|
|
90
|
+
'persona': frontmatter.get('persona')
|
|
61
91
|
}
|
|
62
92
|
|
|
63
93
|
# Plain markdown - use content as system prompt
|
|
@@ -85,6 +115,25 @@ def load_agent_definition(file_path: str) -> Dict[str, Any]:
|
|
|
85
115
|
raise ValueError(f"Unsupported file format: {path.suffix}")
|
|
86
116
|
|
|
87
117
|
|
|
118
|
+
def unwrap_secrets(obj: Any) -> Any:
|
|
119
|
+
"""
|
|
120
|
+
Recursively unwrap pydantic SecretStr values into plain strings.
|
|
121
|
+
|
|
122
|
+
Handles nested dicts, lists, tuples, and sets while preserving structure.
|
|
123
|
+
"""
|
|
124
|
+
if isinstance(obj, SecretStr):
|
|
125
|
+
return obj.get_secret_value()
|
|
126
|
+
if isinstance(obj, dict):
|
|
127
|
+
return {k: unwrap_secrets(v) for k, v in obj.items()}
|
|
128
|
+
if isinstance(obj, list):
|
|
129
|
+
return [unwrap_secrets(v) for v in obj]
|
|
130
|
+
if isinstance(obj, tuple):
|
|
131
|
+
return tuple(unwrap_secrets(v) for v in obj)
|
|
132
|
+
if isinstance(obj, set):
|
|
133
|
+
return {unwrap_secrets(v) for v in obj}
|
|
134
|
+
return obj
|
|
135
|
+
|
|
136
|
+
|
|
88
137
|
def build_agent_data_structure(agent_def: Dict[str, Any], toolkit_configs: list,
|
|
89
138
|
llm_model: str, llm_temperature: float, llm_max_tokens: int) -> Dict[str, Any]:
|
|
90
139
|
"""
|
|
@@ -128,7 +177,8 @@ def build_agent_data_structure(agent_def: Dict[str, Any], toolkit_configs: list,
|
|
|
128
177
|
if hasattr(toolkit_class, 'toolkit_config_schema'):
|
|
129
178
|
schema = toolkit_class.toolkit_config_schema()
|
|
130
179
|
validated_config = schema(**toolkit_config)
|
|
131
|
-
|
|
180
|
+
# Use python mode so SecretStr remains as objects, then unwrap recursively
|
|
181
|
+
validated_dict = unwrap_secrets(validated_config.model_dump(mode="python"))
|
|
132
182
|
validated_dict['type'] = toolkit_config.get('type')
|
|
133
183
|
validated_dict['toolkit_name'] = toolkit_config.get('toolkit_name')
|
|
134
184
|
validated_toolkit_configs.append(validated_dict)
|
|
@@ -168,7 +218,6 @@ def build_agent_data_structure(agent_def: Dict[str, Any], toolkit_configs: list,
|
|
|
168
218
|
'settings': toolkit_config,
|
|
169
219
|
'selected_tools': toolkit_config.get('selected_tools', [])
|
|
170
220
|
})
|
|
171
|
-
|
|
172
221
|
return {
|
|
173
222
|
'instructions': agent_def.get('system_prompt', ''),
|
|
174
223
|
'tools': tools,
|
|
@@ -181,8 +230,6 @@ def build_agent_data_structure(agent_def: Dict[str, Any], toolkit_configs: list,
|
|
|
181
230
|
'model_name': llm_model,
|
|
182
231
|
'max_tokens': llm_max_tokens,
|
|
183
232
|
'temperature': llm_temperature,
|
|
184
|
-
'top_p': 1.0,
|
|
185
|
-
'top_k': 0,
|
|
186
233
|
'integration_uid': None,
|
|
187
234
|
'indexer_config': {
|
|
188
235
|
'ai_model': 'langchain_openai.ChatOpenAI',
|
|
@@ -193,5 +240,6 @@ def build_agent_data_structure(agent_def: Dict[str, Any], toolkit_configs: list,
|
|
|
193
240
|
}
|
|
194
241
|
}
|
|
195
242
|
},
|
|
196
|
-
'agent_type': agent_def.get('agent_type', 'react')
|
|
243
|
+
'agent_type': agent_def.get('agent_type', 'react'),
|
|
244
|
+
'persona': agent_def.get('persona', 'quirky')
|
|
197
245
|
}
|
alita_sdk/cli/agent_ui.py
CHANGED
|
@@ -79,12 +79,23 @@ def print_help():
|
|
|
79
79
|
padding=(0, 1),
|
|
80
80
|
)
|
|
81
81
|
|
|
82
|
-
table.add_column("Command", style="bold yellow", no_wrap=True, width=
|
|
82
|
+
table.add_column("Command", style="bold yellow", no_wrap=True, width=16)
|
|
83
83
|
table.add_column("Description", style="white")
|
|
84
84
|
|
|
85
85
|
table.add_row("/clear", "Clear conversation history")
|
|
86
86
|
table.add_row("/history", "Show conversation history")
|
|
87
87
|
table.add_row("/save", "Save conversation to file")
|
|
88
|
+
table.add_row("/agent", "Switch to a different agent or direct chat")
|
|
89
|
+
table.add_row("/model", "Switch to a different model (preserves history)")
|
|
90
|
+
table.add_row("/reload", "Reload agent from file (hot reload)")
|
|
91
|
+
table.add_row("/mode", "Set approval mode: always, auto, yolo")
|
|
92
|
+
table.add_row("/dir [add|rm] <path>", "Add/remove/list allowed directories")
|
|
93
|
+
table.add_row("/inventory <path>", "Load inventory/knowledge graph from JSON file")
|
|
94
|
+
table.add_row("/session", "List or resume previous sessions with plans")
|
|
95
|
+
table.add_row("/add_mcp", "Add an MCP server (preserves history)")
|
|
96
|
+
table.add_row("/add_toolkit", "Add a toolkit (preserves history)")
|
|
97
|
+
table.add_row("/rm_mcp", "Remove an MCP server")
|
|
98
|
+
table.add_row("/rm_toolkit", "Remove a toolkit")
|
|
88
99
|
table.add_row("/help", "Show this help")
|
|
89
100
|
table.add_row("exit", "End conversation")
|
|
90
101
|
|
|
@@ -92,55 +103,106 @@ def print_help():
|
|
|
92
103
|
console.print()
|
|
93
104
|
|
|
94
105
|
|
|
95
|
-
def print_welcome(agent_name: str,
|
|
96
|
-
"""Print combined welcome banner with logo, agent info, and help."""
|
|
106
|
+
def print_welcome(agent_name: str, model: str = "gpt-4o", temperature: float = 0.1, mode: str = "always"):
|
|
107
|
+
"""Print combined welcome banner with logo, agent info, and help in two columns."""
|
|
97
108
|
|
|
98
109
|
version = get_version()
|
|
99
110
|
|
|
100
|
-
#
|
|
101
|
-
|
|
111
|
+
# Mode display with color
|
|
112
|
+
mode_colors = {'always': 'yellow', 'auto': 'green', 'yolo': 'red'}
|
|
113
|
+
mode_color = mode_colors.get(mode, 'white')
|
|
102
114
|
|
|
103
|
-
#
|
|
115
|
+
# Left column: Logo + version + agent info
|
|
116
|
+
left_content = Text()
|
|
104
117
|
for line in ALITA_LOGO:
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
# Commands
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
118
|
+
left_content.append(line + "\n", style="bold cyan")
|
|
119
|
+
left_content.append(" CLI ", style="dim")
|
|
120
|
+
left_content.append(f"v{version}\n\n", style="bold white")
|
|
121
|
+
left_content.append("● ", style="bold green")
|
|
122
|
+
left_content.append("Agent: ", style="bold white")
|
|
123
|
+
left_content.append(f"{agent_name}\n", style="bold cyan")
|
|
124
|
+
left_content.append("● ", style="bold green")
|
|
125
|
+
left_content.append("Model: ", style="bold white")
|
|
126
|
+
left_content.append(f"{model}", style="cyan")
|
|
127
|
+
left_content.append(" | ", style="dim")
|
|
128
|
+
left_content.append("Temp: ", style="bold white")
|
|
129
|
+
left_content.append(f"{temperature}\n", style="cyan")
|
|
130
|
+
left_content.append("● ", style="bold green")
|
|
131
|
+
left_content.append("Mode: ", style="bold white")
|
|
132
|
+
left_content.append(f"{mode}\n", style=f"bold {mode_color}")
|
|
133
|
+
|
|
134
|
+
# Right column: Commands
|
|
135
|
+
right_content = Text()
|
|
136
|
+
right_content.append("\n") # Align with logo
|
|
137
|
+
right_content.append("/help", style="bold yellow")
|
|
138
|
+
right_content.append(" Show all commands\n", style="dim")
|
|
139
|
+
right_content.append("/agent", style="bold yellow")
|
|
140
|
+
right_content.append(" Switch agent\n", style="dim")
|
|
141
|
+
right_content.append("/model", style="bold yellow")
|
|
142
|
+
right_content.append(" Switch model\n", style="dim")
|
|
143
|
+
right_content.append("/reload", style="bold yellow")
|
|
144
|
+
right_content.append(" Reload agent file\n", style="dim")
|
|
145
|
+
right_content.append("/mode", style="bold yellow")
|
|
146
|
+
right_content.append(" Set approval mode\n", style="dim")
|
|
147
|
+
right_content.append("/dir", style="bold yellow")
|
|
148
|
+
right_content.append(" Add/list directories\n", style="dim")
|
|
149
|
+
right_content.append("/session", style="bold yellow")
|
|
150
|
+
right_content.append(" List/resume sessions\n", style="dim")
|
|
151
|
+
right_content.append("/inventory", style="bold yellow")
|
|
152
|
+
right_content.append(" Load knowledge graph\n", style="dim")
|
|
153
|
+
right_content.append("/add_mcp", style="bold yellow")
|
|
154
|
+
right_content.append(" Add MCP server\n", style="dim")
|
|
155
|
+
right_content.append("/add_toolkit", style="bold yellow")
|
|
156
|
+
right_content.append(" Add toolkit\n", style="dim")
|
|
157
|
+
right_content.append("exit", style="bold yellow")
|
|
158
|
+
right_content.append(" End conversation\n", style="dim")
|
|
159
|
+
|
|
160
|
+
# Create two-column layout
|
|
161
|
+
columns = Columns([left_content, right_content], padding=(0, 4), expand=False)
|
|
128
162
|
|
|
129
163
|
console.print()
|
|
130
164
|
console.print(Panel(
|
|
131
|
-
|
|
165
|
+
columns,
|
|
132
166
|
box=box.DOUBLE,
|
|
133
167
|
border_style="cyan",
|
|
134
|
-
padding=(
|
|
168
|
+
padding=(1, 2),
|
|
135
169
|
))
|
|
136
170
|
console.print()
|
|
137
171
|
|
|
138
172
|
|
|
173
|
+
def render_plan(plan_state) -> None:
|
|
174
|
+
"""Render a plan with checkboxes."""
|
|
175
|
+
if not plan_state or not plan_state.steps:
|
|
176
|
+
return
|
|
177
|
+
|
|
178
|
+
console.print(plan_state.render())
|
|
179
|
+
console.print()
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def render_approval_prompt(tool_name: str, tool_args: dict, truncate: int = 60) -> str:
|
|
183
|
+
"""
|
|
184
|
+
Render an approval prompt for a tool call.
|
|
185
|
+
|
|
186
|
+
Returns the formatted string for display in the input box.
|
|
187
|
+
"""
|
|
188
|
+
# Format args as a compact string
|
|
189
|
+
args_str = ", ".join(f"{k}={repr(v)[:truncate]}" for k, v in tool_args.items())
|
|
190
|
+
if len(args_str) > 80:
|
|
191
|
+
args_str = args_str[:77] + "..."
|
|
192
|
+
|
|
193
|
+
return f"🔧 {tool_name}: {args_str}"
|
|
194
|
+
|
|
195
|
+
|
|
139
196
|
def display_output(agent_name: str, message: str, output: str):
|
|
140
197
|
"""Display agent output with markdown rendering if applicable."""
|
|
141
198
|
console.print(f"\n[bold cyan]🤖 Agent: {agent_name}[/bold cyan]\n")
|
|
142
199
|
console.print(f"[bold]Message:[/bold] {message}\n")
|
|
143
200
|
console.print("[bold]Response:[/bold]")
|
|
201
|
+
|
|
202
|
+
# Ensure output is a string
|
|
203
|
+
if not isinstance(output, str):
|
|
204
|
+
output = str(output)
|
|
205
|
+
|
|
144
206
|
if any(marker in output for marker in ['```', '**', '##', '- ', '* ']):
|
|
145
207
|
console.print(Markdown(output))
|
|
146
208
|
else:
|